package ru.pb.dao.game.mysql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.log4j.Logger;

import ru.pb.game.dao.ClanDAO;
import ru.pb.game.dao.PlayerDAO;
import ru.pb.game.objects.model.clan.Clan;
import ru.pb.game.objects.model.players.Player;
import ru.pb.global.dao.DAOManager;
import ru.pb.global.dao.annotations.DAO;
import ru.pb.global.data.model.ClanInfo;
import ru.pb.global.data.model.PlayerInfo;
import ru.pb.global.dbc.DatabaseFactory;
import ru.pb.global.dbc.DatabaseUtils;

/**
 * @author: Felixx
 */
@DAO(database = "MySQL")
public class PlayerDAOImpl implements PlayerDAO
{
	private static final Logger _log = Logger.getLogger(PlayerDAO.class);

	private ClanDAO _clanDao;

	public void init()
	{
		_clanDao = DAOManager.getDAOImpl(ClanDAO.class);
	}

	@Override
	public boolean insert(Player player)
	{
		Connection con = null;
		PreparedStatement statement = null;
		try
		{
			con = DatabaseFactory.getInstance().newConnection();
			statement = con.prepareStatement("INSERT INTO players (account,player_id,player_name,name_color,clan_id,rank,gp,exp,pc_cafe,fights_s,fights_win_s,fights_lost_s,kills_count_s,deaths_count_s,escapes_s,fights_ns,fights_win_ns,fights_lost_ns,kills_count_ns,deaths_count_ns,escapes_ns,create_date) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
			statement.setString(1, player.getAccount());
			statement.setInt(2, player.getObjectId());
			statement.setString(3, player.getName());

			PlayerInfo info = player.getPlayerInfos();
			statement.setInt(4, info.getNameColor(false));
			statement.setInt(5, info.getClanInfo().getClanId());
			statement.setInt(6, info.getRank());
			statement.setInt(7, info.getGamePoint());
			statement.setInt(8, info.getExp());
			statement.setInt(9, info.getPcCafe());

			statement.setInt(10, info.getFights(true));
			statement.setInt(11, info.getWinFights(true));
			statement.setInt(12, info.getLostFights(true));
			statement.setInt(13, info.getKills(true));
			statement.setInt(14, info.getDeaths(true));
			statement.setInt(15, info.getEscapes(true));

			statement.setInt(16, info.getFights(false));
			statement.setInt(17, info.getWinFights(false));
			statement.setInt(18, info.getLostFights(false));
			statement.setInt(19, info.getKills(false));
			statement.setInt(20, info.getDeaths(false));
			statement.setInt(21, info.getEscapes(false));

			statement.setLong(22, System.currentTimeMillis() / 1000);
			statement.executeUpdate();

			updateMoney(player.getAccount(), player.getPlayerInfos().getMoney(), con);
		}
		catch(final Exception e)
		{
			_log.info("Exception: " + e, e);
			return false;
		}
		finally
		{
			DatabaseUtils.closeDatabaseCS(con, statement);
		}
		return true;
	}

	@Override
	public Player select(String acc)
	{
		Player pl = null;
		Connection con = null;
		PreparedStatement statement = null;
		ResultSet rset = null;
		try
		{
			con = DatabaseFactory.getInstance().newConnection();
			statement = con.prepareStatement("SELECT * FROM players WHERE account=? LIMIT 1");
			statement.setString(1, acc);
			rset = statement.executeQuery();
			if(rset.next())
			{

				PlayerInfo info = new PlayerInfo();

				int player_id = rset.getInt("player_id");
				String playerName = rset.getString("player_name");
				int clan_id = rset.getInt("clan_id");

				pl = new Player(player_id, acc);
				if(clan_id > 0)
				{
					ClanInfo cinfo = _clanDao.select(clan_id, con);
					info.setClanInfo(cinfo);
					pl.setClan(new Clan(cinfo));
				}

				info.setPlayerId(player_id);

				info.setPlayerName(playerName);
				info.setNameColor(rset.getInt("name_color"));

				info.setRank(rset.getInt("rank"));

				info.setGamePoint(rset.getInt("gp"));

				info.setExp(rset.getInt("exp"));

				info.setPcCafe(rset.getInt("pc_cafe"));

				info.setFights(rset.getInt("fights_s"), true);
				info.setFights(rset.getInt("fights_ns"), false);

				info.setWinFights(rset.getInt("fights_win_s"), true);
				info.setWinFights(rset.getInt("fights_win_ns"), false);

				info.setLostFights(rset.getInt("fights_lost_s"), true);
				info.setLostFights(rset.getInt("fights_lost_ns"), false);

				info.setKills(rset.getInt("kills_count_s"), true);
				info.setKills(rset.getInt("kills_count_ns"), false);

				info.setDeaths(rset.getInt("deaths_count_s"), true);
				info.setDeaths(rset.getInt("deaths_count_ns"), false);

				info.setEscapes(rset.getInt("escapes_s"), true);
				info.setEscapes(rset.getInt("escapes_ns"), false);

				info.setCreateDate(rset.getLong("create_date"));
				info.setLastAccess(rset.getInt("lastAccess"));
				info.setOnlineTime(rset.getInt("onlinetime"));
				info.setOnline(rset.getBoolean("online"));

				pl.setPlayerInfos(info);
				pl.getInventory().restoreMe(con);

				pl.getPlayerInfos().setMoney(getMoney(pl.getAccount(), con));
			}
		}
		catch(SQLException e)
		{
			_log.info("SQLException: " + e, e);
		}
		finally
		{
			DatabaseUtils.closeDatabaseCSR(con, statement, rset);
		}
		return pl;
	}

	@Override
	public void update(Player player, boolean fast, boolean isCreate)
	{
		player.storeLock().lock();
		try
		{
			Connection con = null;
			PreparedStatement statement = null;
			try
			{
				con = DatabaseFactory.getInstance().newConnection();
				statement = con.prepareStatement("UPDATE players SET clan_id=?,rank=?,gp=?,exp=?,pc_cafe=?,fights_s=?,fights_win_s=?,fights_lost_s=?,kills_count_s=?,deaths_count_s=?,escapes_s=?, fights_ns=?,fights_win_ns=?,fights_lost_ns=?,kills_count_ns=?,deaths_count_ns=?,escapes_ns=? WHERE player_id=? LIMIT 1");
				statement.setInt(1, player.getClan() != null ? player.getClan().getObjectId() : 0);

				PlayerInfo info = player.getPlayerInfos();

				statement.setInt(2, info.getRank());
				statement.setInt(3, info.getGamePoint());
				statement.setInt(4, info.getExp());
				statement.setInt(5, info.getPcCafe());

				statement.setInt(6, info.getFights(true));
				statement.setInt(7, info.getWinFights(true));
				statement.setInt(8, info.getLostFights(true));
				statement.setInt(9, info.getKills(true));
				statement.setInt(10, info.getDeaths(true));
				statement.setInt(11, info.getEscapes(true));

				statement.setInt(12, info.getFights(false));
				statement.setInt(13, info.getWinFights(false));
				statement.setInt(14, info.getLostFights(false));
				statement.setInt(15, info.getKills(false));
				statement.setInt(16, info.getDeaths(false));
				statement.setInt(17, info.getEscapes(false));

				statement.setInt(18, player.getObjectId());

				statement.executeUpdate();

				if( !fast)
				{
					// _playerEffectsDAO.deleteAndInsert(con, player);
					// _playerSkillsSaveDAO.deleteAndInsert(con, player);

					// _playerBlockListDAO.deleteAndInsert(con, player);
					// _playerVoteDAO.update(con, player);

					// player.getInventory().updateMe(con);
					// player.getQuestInventory().updateMe(con);
				}
			}
			catch(final Exception e)
			{
				_log.info("Exception: " + e, e);
			}
			finally
			{
				DatabaseUtils.closeDatabaseCS(con, statement);
			}
		}
		finally
		{
			player.storeLock().unlock();
		}
	}

	@Override
	public void updateOnline(Player player)
	{
		Connection con = null;
		PreparedStatement statement = null;
		try
		{
			con = DatabaseFactory.getInstance().newConnection();
			statement = con.prepareStatement("UPDATE players SET online=?, lastAccess=? WHERE player_id=?");
			statement.setInt(1, player.getOnlineType());
			statement.setLong(2, System.currentTimeMillis() / 1000);
			statement.setInt(3, player.getObjectId());
			statement.execute();
		}
		catch(final Exception e)
		{
			_log.warn("could not set player online status:" + e, e);
		}
		finally
		{
			DatabaseUtils.closeDatabaseCS(con, statement);
		}
	}

	@Override
	public int getMoney(String acc, Connection con)
	{
		boolean needCloseConnection = con == null;

		PreparedStatement statement = null;
		ResultSet rset = null;
		try
		{
			if(needCloseConnection)
				con = DatabaseFactory.getInstance().newConnection();

			con = DatabaseFactory.getInstance().newConnection();
			statement = con.prepareStatement("SELECT money FROM accounts WHERE login=? LIMIT 1");
			statement.setString(1, acc);
			rset = statement.executeQuery();
			if(rset.next())
			{
				return rset.getInt("money");
			}
		}
		catch(SQLException e)
		{
			_log.info("SQLException: " + e, e);
		}
		finally
		{
			if(needCloseConnection)
				DatabaseUtils.closeConnection(con);
			DatabaseUtils.closeDatabaseSR(statement, rset);
		}

		return 0;
	}

	@Override
	public void updateMoney(String acc, int money, Connection con)
	{
		boolean needCloseConnection = con == null;
		PreparedStatement stmt = null;
		try
		{
			if(needCloseConnection)
				con = DatabaseFactory.getInstance().newConnection();

			con = DatabaseFactory.getInstance().newConnection();
			stmt = con.prepareStatement("UPDATE accounts SET money = ? WHERE login = ? LIMIT 1");
			stmt.setLong(1, money);
			stmt.setString(2, acc);
			stmt.execute();
		}
		catch(SQLException e)
		{
			_log.info("SQLException: " + e, e);
		}
		finally
		{
			if(needCloseConnection)
				DatabaseUtils.closeConnection(con);
			DatabaseUtils.closeStatement(stmt);
		}
	}
}